﻿/*
 * @author Lee 
 * Time: 20180403 
 * Abstract: SharePoint API的二次封装
 */

using Microsoft.SharePoint;
using Microsoft.SharePoint.Taxonomy;
using Microsoft.SharePoint.Utilities;
using System;
using System.Collections.Generic;
using System.IO;

namespace SharePointHelper.DLL.SSOM
{
    public class Item
    {
        #region 获取calendar中一段时间内的events
        /// <summary>
        /// 获取calendar中一段时间内的events
        /// </summary>
        /// <param name="eventCalendar"></param>
        /// <param name="startTime">"10/24/2017 09:00 am"</param>
        /// <param name="endTime">"10/24/2017 11:30 am"</param>
        /// <returns></returns>
        public static SPListItemCollection GetEventsBetweenTimeSlot(SPList eventCalendar,string startTime, string endTime)
        {
            DateTime startDateTime = DateTime.Parse(startTime);
            DateTime endDateTime = DateTime.Parse(endTime);
            string startDateTimeString = SPUtility.CreateISO8601DateTimeFromSystemDateTime(startDateTime);
            string endDateTimeString = SPUtility.CreateISO8601DateTimeFromSystemDateTime(endDateTime);
            SPQuery query = new SPQuery();
            query.RowLimit = 3;
            query.ExpandRecurrence = true;            
            query.Query = "<Where>" +                    
                              "<And>" +
                                "<Geq>" +
                                    "<FieldRef Name='EndDate' />" +
                                    "<Value Type='DateTime' IncludeTimeValue='True'>" +
                                        startDateTimeString +
                                    "</Value>" +
                                "</Geq>" +
                                "<Leq>" +
                                    "<FieldRef Name='EventDate' />" +
                                    "<Value Type='DateTime' IncludeTimeValue='True'>" +
                                        endDateTimeString +
                                    "</Value>" +
                                "</Leq>" +
                              "</And>" +
                            "</Where>" +
                            "<OrderBy>" +
                                "<FieldRef Name='EventDate' />" +
                            "</OrderBy>";            

            SPListItemCollection itemColl = eventCalendar.GetItems(query);

            return itemColl;
        }
        #endregion

        #region 给List Item添加附件Attachment
        /// <summary>
        /// 给List Item添加附件Attachment
        /// </summary>
        /// <param name="path"></param>
        /// <param name="siteURL"></param>
        /// <param name="listName"></param>
        /// <param name="itemId"></param>
        public static void addAttachment(string path,string siteURL, string listName, int itemId)
        {
            using(SPSite spSite = new SPSite(siteURL)){
                SPWeb spWeb = spSite.RootWeb;
                SPList list = spWeb.Lists[listName];
                SPListItem item = list.Items.GetItemById(itemId);
                SPAttachmentCollection attachments = item.Attachments;
                FileStream stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                byte[] bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);

                //get file name
                string fileName = Path.GetFileName(stream.Name);

                //declare a bool variable
                bool IsAlreadyInUse = false;
               
                //check if the file already exists
                for (int x = 0; x < attachments.Count; x++)
                {
                    string attachmentName = attachments[x];
                    if (attachmentName.Equals(fileName))
                    {                  
                        IsAlreadyInUse = true;
                        break;
                    }
                }

                //file not exists
                if (!IsAlreadyInUse)
                {
                    attachments.Add(fileName, bytes);
                    item.Update();
                }
                //file exists
                else
                {
                    Console.WriteLine("File Already Exists");
                }
            }
        }//method end
        #endregion

        #region 通过name查找并获取子站点
        /// <summary>
        /// 通过name查找获取子站点
        /// </summary>
        /// <param name="rootWeb"></param>
        /// <param name="subSiteName"></param>
        /// <returns></returns>
        public static SPWeb FindSubSite(SPWeb rootWeb, string subSiteName)
        {
            SPWebCollection webCollection = rootWeb.Webs;
            if (webCollection.Count > 0)
            {
                SPWeb subsite = null;
                foreach (SPWeb web in webCollection)
                {
                    if (web.Name == subSiteName)
                    {
                        subsite = web;
                        break;
                    }
                    else if (web.Webs.Count > 0)
                    {
                        subsite = FindSubSite(web, subSiteName);
                        break;
                    }

                }
                return subsite;

            }
            else
            {
                return null;
            }
        }
        #endregion

        #region 获取某个document library中一段时间内创建或修改的file
        /// <summary>
        /// 获取某个document library中一段时间内创建或修改的file
        /// </summary>
        /// <param name="siteUrl"></param>
        /// <param name="docLibName"></param>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <returns></returns>
        public static List<SPFile> getFileModifiedOrCreatedInPeriodOfTime(string siteUrl, string docLibName, DateTime startTime, DateTime endTime)
        {
            List<SPFile> list = null;
            string url = siteUrl;
            SPSite spSite = new SPSite(url);
            SPWeb spWeb = spSite.RootWeb;
            SPList docLibList = spWeb.Lists[docLibName];

            DateTime startDateTime = startTime;
            DateTime endDateTime = endTime;

            SPListItemCollection folderItemCollection = docLibList.Folders;

            foreach (SPListItem item in folderItemCollection)
            {
                SPFileCollection files = item.Folder.Files;
                foreach (SPFile file in files)
                {

                    DateTime createdTime = file.TimeCreated;
                    DateTime modifiedTime = file.TimeLastModified;
                    if ((startDateTime < createdTime && createdTime < endDateTime) || (startDateTime < modifiedTime && modifiedTime < endDateTime))
                    {
                        list.Add(file);
                    }
                }
            }


            SPFolder folder = spWeb.GetFolder(docLibList.RootFolder.Url + "/MainFolder/SubFolder");
            foreach (SPFile file in folder.Files)
            {

                DateTime createdTime = file.TimeCreated;
                DateTime modifiedTime = file.TimeLastModified;
                if ((startDateTime < createdTime && createdTime < endDateTime) || (startDateTime < modifiedTime && modifiedTime < endDateTime))
                {
                    //string name = file.Author.Name;
                    //string path = file.Url;
                    //Console.WriteLine("Name: " + name + "--------" + "Path: " + path);
                    list.Add(file);
                }

            }
            return list;           
        }
        #endregion

        #region 创建一个list item，是否保存。
        /// <summary>
        /// 创建一个list item，是否保存。
        /// </summary>
        /// <param name="list">List to add item to</param>
        /// <param name="title"></param>
        /// <param name="isSave">is save to database</param>
        /// <returns></returns>
        public static SPListItem CreateItem(SPList list, string title, bool isSave)
        {
            SPListItem newItem = null;
            try
            {
                // 初始化
                if (list == null) { throw new Exception("SPList passed is null"); }

                newItem = list.Items.Add();
                newItem["Title"] = title;

                // 保存
                if (isSave) { newItem.Update(); }
            }
            catch (Exception ex)
            {
                newItem = null;
            }
            return newItem;
        }
        #endregion

        #region 任务枚举
        /// <summary>
        /// 任务优先级
        /// </summary>
        public enum TaskPriority
        {
            High = 1,
            Normal,
            Low,
        }

        /// <summary>
        /// 任务状态
        /// </summary>
		public enum TaskStatus
        {
            Not_Started,
            In_Progress,
            Completed,
            Deferred,
            Waiting_on_someone_else,
        }
        #endregion

        #region 创建一个任务列表item
        /// <summary>
        /// 创建一个任务列表item
        /// </summary>
        /// <param name="taskList"></param>
        /// <param name="title"></param>
        /// <param name="assignedTo"></param>
        /// <param name="priority"></param>
        /// <param name="status"></param>
        /// <param name="percentComplete"></param>
        /// <param name="startDate"></param>
        /// <param name="dueDate"></param>
        /// <param name="predecessors"></param>
        public static void CreateTaskItem(SPList taskList, string title, SPUser assignedTo, TaskPriority priority,
            TaskStatus status, float? percentComplete, DateTime? startDate, DateTime? dueDate, int? predecessors)
        {
            try
            {
                // init
                if (taskList == null) { throw new Exception("SPList passed is null"); }
                if (string.IsNullOrEmpty(title)) { throw new Exception("Title passed is null"); }
                if (percentComplete == null) { percentComplete = 0; }
                if (startDate == null || startDate == DateTime.MinValue) { startDate = DateTime.Now; }
                if (dueDate == null || dueDate == DateTime.MinValue) { dueDate = DateTime.Now; }


                // assigned to
                if (assignedTo == null)
                {
                    if (SPContext.Current != null && SPContext.Current.Web != null)
                    {
                        assignedTo = SPContext.Current.Web.CurrentUser;
                    }
                    else
                    {
                        throw new Exception("Assigned to user passed is null and failed to get current SPUser");
                    }
                }

                SPListItem newItem = CreateItem(taskList, title, false);
                newItem["AssignedTo"] = assignedTo;
                newItem["Priority"] = priority.ToString();
                newItem["Status"] = status.ToString().Replace("_", " ");
                newItem["PercentComplete"] = (float)percentComplete;

                if (predecessors != null && predecessors > 0)
                {
                    newItem["Predecessors"] = (int)predecessors;
                }

                newItem["StartDate"] = startDate;
                newItem["DueDate"] = dueDate;

                // save
                newItem.Update();
            }
            catch (Exception ex)
            {
                Log.WriteError("7t98pyflukdfguydrtu", ex);
            }
        }
        #endregion

        #region 通过相对URL路径获取document library item
        /// <summary>
        /// 通过相对URL路径获取document library item
        /// http://blog.mastykarz.nl/inconvenient-spweb-getlistitem-exception-hresult-0x80070001/
        /// </summary>
        /// <param name="web"></param>
        /// <param name="url">相对URL路径</param>
        /// <returns></returns>
        public static SPListItem GetItemByUrl(SPWeb web, string url)
        {
            SPListItem item = null;
            try
            {
                // init
                if (web == null) { web = Web.GetWeb(); }
                if (web == null) { throw new Exception("Failed to get SPWeb from SPContext"); }
                if (string.IsNullOrEmpty(url)) { throw new Exception("Url passed is null"); }

                item = web.GetListItem(url);
            }
            catch (Exception ex)
            {
                Log.WriteError("zdsghfyttdydfxfd", ex, "url: " + url);
                item = null;
            }
            return item;
        }
        #endregion

        #region 通过ID获取List Item
        /// <summary>
        /// 通过ID获取List Item
        /// </summary>
        /// <param name="list"></param>
        /// <param name="itemId"></param>
        /// <returns></returns>
        public static SPListItem GetItemById(SPList list, int itemId)
        {
            SPListItem item = null;
            try
            {
                // init
                if (list == null) { throw new Exception("SPList passed is null"); }

                item = list.GetItemById(itemId);
            }
            catch (Exception ex)
            {
                Log.WriteError("etwew5rsfdaserf", ex, "itemId: " + itemId);
                item = null;
            }
            return item;
        }
        #endregion

        #region 通过GUID获取List Item
        /// <summary>
        /// 通过GUID获取List Item
        /// </summary>
        /// <param name="list"></param>
        /// <param name="uniqueId"></param>
        /// <returns></returns>
        public static SPListItem GetItemByUniqueId(SPList list, Guid uniqueId)
        {
            SPListItem item = null;
            try
            {
                // init
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (uniqueId == null || uniqueId == Guid.Empty) { throw new Exception("UniqueId passed is null"); }

                list.GetItemByUniqueId(uniqueId);
            }
            catch (Exception ex)
            {
                Log.WriteError("sreyt5yewy5u5weews", ex);
                item = null;
            }
            return item;
        }
        #endregion

        #region 根据Title来获取List Item
        /// <summary>
        /// 根据Title来获取List Item（会对item进行遍历，可能会影响性能）
        /// </summary>
        /// <param name="list"></param>
        /// <param name="title"></param>
        /// <returns></returns>
        public static SPListItem GetItemByTitle(SPList list, string title)
        {
            SPListItem item = null;
            try
            {
                // init
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (string.IsNullOrEmpty(title)) { throw new Exception("SPListItem title passed is null"); }


                // get all items with matching title
                SPListItemCollection items = GetItems(list, "Text", "Title", title);
                if (items.Count != 0)
                {
                    item = items[0];
                    if (items.Count > 1)
                    {
                        string duplicateItemsUrls = null;
                        foreach (SPListItem i in items) { duplicateItemsUrls += GetUrl(i, true, false) + "\r\n"; }
                        Log.WriteError("dsgfgdsdrsasdg", "Returned " + items.Count + " items for list: "
                            + list.Title + " using title: " + title + "\r\n\r\nItems with Same Title:\r\n"
                            + duplicateItemsUrls);
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("ytfyggdfjf", ex, "title: " + title);
                item = null;
            }
            return item;
        }
        #endregion

        #region 根据某个field（column）的值来获取item
        /// <summary>
        /// 根据某个field（column）的值来获取item
        /// </summary>
        /// <param name="list"></param>
        /// <param name="fieldType">If null, 默认是 "Text"</param>
        /// <param name="fieldName"></param>
        /// <param name="fieldValue"></param>
        /// <returns></returns>
        public static SPListItem GetItemByFieldValue(SPList list, string fieldType, string fieldName, string fieldValue)
        {
            SPListItem item = null;
            try
            {
                // init
                if (list == null) { throw new Exception("SPList passed is null"); }

                // get all items with matching title
                SPListItemCollection items = GetItems(list, fieldType, fieldName, fieldValue);
                if (items.Count != 0)
                {
                    item = items[0];
                    if (items.Count > 0)
                    {
                        Log.WriteError("srtudtsrdsdrtr", "Returned more than one item for list: "
                            + list.Title + " using field: " + fieldName + " with value: " + fieldValue);
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("futdfjhdddtyyt", ex, "type: " + fieldType + " name: " + fieldName + " value: " + fieldValue);
                item = null;
            }
            return item;
        }
        #endregion

        #region 根据CAML Query来获取list数据
        /// <summary>
        /// 根据CAML Query来获取list数据，若SPQuery==null，则返回所有数据
        /// </summary>
        /// <param name="list"></param>
        /// <param name="query">若SPQuery==null，则返回所有数据</param>
        /// <returns></returns>
        public static SPListItemCollection GetItems(SPList list, SPQuery query)
        {
            string queryText = null;
            SPListItemCollection items = null;
            try
            {
                // init
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (query == null)
                {
                    // query to select all
                    query = new SPQuery();
                }
                else
                {
                    queryText = query.Query;
                }

                items = list.GetItems(query);
            }
            catch (Exception ex)
            {
                Log.WriteError("ertyfdfdsr", ex, "query: " + queryText);
                items = null;
            }
            return items;
        }
        #endregion

        #region 根据某个field（column）的值来获取匹配的ListItemCollection
        /// <summary>
        /// 根据某个field（column）的值来获取匹配的ListItemCollection
        /// </summary>
        /// <param name="list"></param>
        /// <param name="fieldType">如果是null, 默认是 "Text"</param>
        /// <param name="fieldName"></param>
        /// <param name="fieldValue"></param>
        /// <returns></returns>
        public static SPListItemCollection GetItems(SPList list, string fieldType, string fieldName, string fieldValue)
        {
            SPListItemCollection items = null;
            string queryText = null;
            try
            {
                // init
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (string.IsNullOrEmpty(fieldName)) { throw new Exception("Field name is null"); }
                if (string.IsNullOrEmpty(fieldType)) { fieldType = "Text"; }


                // build query
                SPQuery q = new SPQuery();
                q.Query = "<Where><Eq><FieldRef Name='" + fieldName + "' /><Value Type='" + fieldType + "'>"
                    + fieldValue + "</Value></Eq></Where>";
                queryText = q.Query;

                items = list.GetItems(q);
            }
            catch (Exception ex)
            {
                Log.WriteError("drgysreutdr7dsdrrdsz", ex, "CAML: " + queryText);
                items = null;
            }
            return items;
        }
        #endregion

        #region 通过传递一个field(column)的值的集合来搜索多个匹配的item
        /// <summary>
        /// 通过传递一个值集合来搜索多个匹配的item
        /// http://stackoverflow.com/questions/1891303/sql-in-equivalent-in-caml
        /// </summary>
        /// <param name="list"></param>
        /// <param name="fieldType"></param>
        /// <param name="fieldName"></param>
        /// <param name="fieldValues"></param>
        /// <param name="fieldsToReturn">The fields to return for SPListItems in returned collection. Use this if SPListItems contain lots of complex fields like managed metadata</param>
        /// <returns></returns>
        public static SPListItemCollection GetItems(SPList list, string fieldType, string fieldName, object[] fieldValues,
            string[] fieldsToReturn, int pageNumber, int pageSize, ref int totalItems)
        {
            SPListItemCollection items = null;
            string query = null;
            try
            {
                // init
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (string.IsNullOrEmpty(fieldName)) { throw new Exception("Field name is null"); }
                if (string.IsNullOrEmpty(fieldType)) { fieldType = "Text"; }
                if (fieldName == "ID") { fieldType = "Counter"; }
                if (fieldValues == null) { throw new Exception("Fieldvalues passed is null"); }
                if (fieldValues.Length > 500) { throw new Exception("Microsoft SharePoint Limits to 500 items in CAML predicate"); }

                if (fieldValues.Length > 0)
                {
                    // build query
                    query = "<Where><In><FieldRef Name='" + fieldName + "' /><Values>";
                    foreach (var v in fieldValues) { query += "<Value Type='" + fieldType + "'>" + v.ToString() + "</Value>"; }
                    query += "</Values></In></Where>";

                    // call original
                    items = GetItems(list, query, fieldsToReturn, pageNumber, pageSize, ref totalItems);
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("tyuyjfhtddgdrte5tr", ex, "CAML: " + query);
                items = null;
            }
            return items;
        }
        #endregion

        #region 通过传递一个field(column)的值的集合来搜索多个匹配的item
        /// <summary>
        /// Get many items by passing a collection of values to search against
        /// </summary>
        /// <param name="list"></param>
        /// <param name="fieldType"></param>
        /// <param name="fieldName"></param>
        /// <param name="fieldValues"></param>
        /// <returns></returns>
        public static SPListItemCollection GetItems(SPList list, string fieldType, string fieldName, object[] fieldValues)
        {
            // call related member
            int _totalItems = 0;
            return GetItems(list, fieldType, fieldName, fieldValues, null, 0, 0, ref _totalItems);
        }
        #endregion

        #region 根据Id数组获取Item集合
        /// <summary>
        /// 根据Id数组获取Item集合(有column的筛选)
        /// </summary>
        /// <param name="list"></param>
        /// <param name="itemIds"></param>
        /// <param name="orderByFields">field name集合，升序排序</param>
        /// <param name="fieldsToReturn">column筛选</param>
        /// <returns></returns>
        public static SPListItemCollection GetItems(SPList list, int[] itemIds, List<Caml.OrderByField> orderByFields,
            string[] fieldsToReturn)
        {
            SPListItemCollection items = null;
            string queryText = null;
            try
            {
                // 初始化
                if (list == null) { throw new Exception("SPList passed is null"); }


                if (itemIds != null && itemIds.Length > 0)
                {
                    SPQuery q = new SPQuery();

                    foreach (int id in itemIds)
                    {
                        queryText += "<Value Type=\"Counter\">" + id + "</Value>";
                    }
                    queryText = "<Where><In><FieldRef Name=\"ID\" /><Values>" + queryText + "</Values></In></Where>";

                    // 排序
                    if (orderByFields != null && orderByFields.Count > 0)
                    {
                        queryText += "<OrderBy>";
                        foreach (Caml.OrderByField f in orderByFields)
                        {
                            if (!string.IsNullOrEmpty(f.FieldName))
                            {
                                queryText += "<FieldRef Name='" + f.FieldName + "' Ascending='" + !f.IsDescending + "' />";
                            }
                        }
                        queryText += "</OrderBy>";
                    }
                    q.Query = queryText;

                    // 设置view的fields
                    if (fieldsToReturn != null && fieldsToReturn.Length > 0) { q.ViewFields = Caml.FormatSPQueryViewFields(fieldsToReturn); }

                    items = GetItems(list, q);
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("drgysreutdr7dsdrrdsz", ex, "CAML: " + queryText + " ids: "
                    + Utilities.ConvertArrayToString(itemIds));
                items = null;
            }
            return items;
        }
        #endregion   

        #region 根据Id数组获取Item集合
        /// <summary>
        /// 根据Id数组获取Item集合
        /// </summary>
        /// <param name="list"></param>
        /// <param name="itemIds"></param>
        /// <returns></returns>
        public static SPListItemCollection GetItems(SPList list, int[] itemIds)
        {
            return GetItems(list, itemIds, null, null);
        }
        #endregion

        #region 根据Id数组获取Item集合
        /// <summary>
        /// 根据Id数组获取Item集合
        /// </summary>
        /// <param name="list"></param>
        /// <param name="itemIds"></param>
        /// <param name="orderByFields">field name集合</param>
        /// <returns></returns>
        public static SPListItemCollection GetItems(SPList list, int[] itemIds, List<Caml.OrderByField> orderByFields)
        {
            return GetItems(list, itemIds, orderByFields, null);
        }
        #endregion

        #region 将SPListItemCollection 转化成 List（会进行遍历）
        /// <summary>
        /// 将SPListItemCollection 转化成 List（会进行遍历）<SPListItem>
        /// </summary>
        /// <param name="items"></param>
        /// <returns></returns>
        public static List<SPListItem> ConvertSPListItemCollectionToGenericCollection(SPListItemCollection items)
        {
            List<SPListItem> itemsConverted = null;
            if (items != null)
            {
                itemsConverted = new List<SPListItem>();
                foreach (SPListItem item in items)
                {
                    itemsConverted.Add(item);
                }

                if (items.Count != itemsConverted.Count)
                {
                    Log.WriteError("57rtythngddsfdsre5ftRew", "Failed to convert SPListItemCollection to generic collection. items.count passed: "
                        + items.Count + ", itemsConverted.Count: " + itemsConverted.Count);
                }
            }
            return itemsConverted;
        }
        #endregion

        #region 对item集合进行分页（高效分页）
        /// <summary>
        /// 对item集合进行分页（高效分页）
        /// http://khaled-abrass.blogspot.com/2009/10/custom-paging-in-sharepoint-list.html
        /// </summary>
        /// <param name="list"></param>
        /// <param name="query">CAML query (非Query标签!)</param>
        /// <param name="fieldsToReturn">筛选fields</param>
        /// <param name="pageNumber">页码，如果是0，则默认是1</param>
        /// <param name="pageSize">分页size
        /// </param>
        /// <param name="totalItems">查询所返回的所有Item的数量</param>
        /// <returns></returns>
        public static SPListItemCollection GetItems(SPList list, string query, string[] fieldsToReturn,
            int pageNumber, int pageSize, ref int totalItems)
        {
            SPListItemCollection items = null;
            try
            {
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (pageNumber == 0) { pageNumber = 1; }

                SPQuery queryTotalItems = new SPQuery();
                if (!string.IsNullOrEmpty(query)) { queryTotalItems.Query = query; }
                queryTotalItems.ViewAttributes = "Scope='RecursiveAll'";
                queryTotalItems.ViewFields = Utilities.FormatSPQueryViewFields(new string[] { "ID" });
                SPListItemCollection totalItemsCollection = list.GetItems(queryTotalItems);
                if (totalItemsCollection != null)
                {
                    totalItems = totalItemsCollection.Count;
                    totalItemsCollection = null;
                }
                queryTotalItems = null;

                if (totalItems != 0)
                {
                    SPListItemCollectionPosition position = null;
                    if (pageNumber > 1)
                    {
                        // 获取字段按
                        string[] fieldsOrderBy = Caml.GetOrderByFieldsFromQuery(query);

                        // 获取上一页最后一项的ID
                        SPQuery queryPreviousItem = new SPQuery();
                        if (!string.IsNullOrEmpty(query)) { queryPreviousItem.Query = query; }
                        queryPreviousItem.ViewAttributes = "Scope='RecursiveAll'";
                        queryPreviousItem.ViewFields = Utilities.FormatSPQueryViewFields(fieldsOrderBy);
                        queryPreviousItem.RowLimit = (uint)(pageSize * (pageNumber - 1));
                        SPListItemCollection previousItemsCollection = list.GetItems(queryPreviousItem);
                        queryPreviousItem = null;

                        // 为排序获取字段的值
                        string orderByFieldValues = string.Empty;
                        if (fieldsOrderBy != null && fieldsOrderBy.Length > 0)
                        {
                            foreach (string f in fieldsOrderBy)
                            {
                                orderByFieldValues += "&p_" + f + "="
                                    + Field.GetTextValue(previousItemsCollection[previousItemsCollection.Count - 1], f);
                            }
                        }

                        // 创建分页信息，用于检索基于分页的项
                        position = new SPListItemCollectionPosition(
                            "Paged=TRUE&p_ID=" + previousItemsCollection[previousItemsCollection.Count - 1].ID
                            + orderByFieldValues);
                    }

                    SPQuery queryFinal = new SPQuery();
                    if (!string.IsNullOrEmpty(query)) { queryFinal.Query = query; }
                    if (fieldsToReturn != null && fieldsToReturn.Length > 0)
                    {
                        queryFinal.ViewAttributes = "Scope='RecursiveAll'";
                        queryFinal.ViewFields = Utilities.FormatSPQueryViewFields(fieldsToReturn);
                    }
                    if (pageSize > 0) { queryFinal.RowLimit = Convert.ToUInt32(pageSize); }

                    // 检查页面索引== 1，这意味着是否需要SPListItemCollectionPosition
                    if (pageNumber > 1 && position != null)
                    {
                        queryFinal.ListItemCollectionPosition = position;
                    }

                    // Execute
                    items = list.GetItems(queryFinal);

                }
            }
            catch (Exception ex)
            {
                Log.WriteError("ertyfdfds5uietyfthdsfVVsr", ex);
                items = null;
            }
            return items;
        }
        #endregion

        #region 获取包含指定wssid的item的集合
        /// <summary>
        /// 获取包含指定wssid的item的集合
        /// </summary>
        /// <param name="list"></param>
        /// <param name="wssId"></param>
        /// <returns></returns>
        public static SPListItemCollection GetItemsByTerm(SPList list, string fieldname, int wssId,
            string[] fieldsToReturn, List<Caml.OrderByField> orderByFields)
        {
            SPListItemCollection items = null;
            try
            {
                // 初始化
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (wssId == 0) { throw new Exception("wssId passed is 0"); }
                if (!Field.IsExist(list, fieldname)) { throw new Exception("Invalid fieldname: " + fieldname); }


                // 调用
                items = GetItemsByTerms(list, fieldname, new List<int>() { wssId }, fieldsToReturn, orderByFields);

            }
            catch (Exception ex)
            {
                Log.WriteError("dfxhhkvdfhsresrrd", ex, "wssId: " + wssId);
                items = null;
            }
            return items;
        }


        /// <summary>
        /// 获取包含指定wssid的item的集合
		/// </summary>
		/// <param name="list"></param>
		/// <param name="fieldname"></param>
		/// <param name="wssId"></param>
		/// <returns></returns>
		public static SPListItemCollection GetItemsByTerm(SPList list, string fieldname, int wssId)
        {
            // 调用
            return GetItemsByTerm(list, fieldname, wssId, null, null);
        }
        #endregion

        #region 获取包含指定term的item集合
        /// <summary>
		/// 获取包含指定term的item集合
		/// </summary>
		/// <param name="list"></param>
		/// <param name="fieldname"></param>
		/// <param name="term"></param>
		/// <returns></returns>
		public static SPListItemCollection GetItemsByTerm(SPList list, string fieldname, Term term)
        {
            SPListItemCollection items = null;
            try
            {
                // 初始化
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (term == null) { throw new Exception("Term passed is null"); }


                // 获取term的ssid
                int? wssId = Taxonomy.GetWssId(list.ParentWeb, term);
                // if (wssId == null) { throw new Exception("Failed to get wssId for term: " + term.Name); }

                // 调用
                if (wssId != null) { items = GetItemsByTerm(list, fieldname, wssId.Value); }
            }
            catch (Exception ex)
            {
                Log.WriteError("ertgrdsswe4a45", ex);
                items = null;
            }
            return items;
        }
        #endregion

        #region 获取包含指定taxonomy field value的item集合
        /// <summary>
		/// 获取包含指定taxonomy field value的item集合
		/// </summary>
		/// <param name="list"></param>
		/// <param name="fieldname"></param>
		/// <param name="taxonomyFieldValue"></param>
		/// <returns></returns>
		public static SPListItemCollection GetItemsByTerm(SPList list, string fieldname,
            TaxonomyFieldValue taxonomyFieldValue)
        {
            SPListItemCollection items = null;
            try
            {
                // 初始化
                if (taxonomyFieldValue == null) { throw new Exception("Term passed is null"); }

                // 执行
                items = GetItemsByTerm(list, fieldname, taxonomyFieldValue.WssId);
            }
            catch (Exception ex)
            {
                Log.WriteError("tsydhfydfsserd5", ex);
                items = null;
            }
            return items;
        }
        #endregion

        #region 获取匹配多个wssid的item的集合
        /// <summary>
        /// 获取匹配多个wssid的item的集合
		/// </summary>
		/// <param name="list"></param>
		/// <param name="fieldname"></param>
		/// <param name="termIds"></param>
		/// <param name="fieldsToReturn"></param>
		/// <param name="orderBy"></param>
		/// <returns></returns>
		public static SPListItemCollection GetItemsByTerms(SPList list, string fieldname, List<int> wssIds,
            string[] fieldsToReturn, List<Caml.OrderByField> orderByFields)
        {
            SPListItemCollection items = null;
            try
            {
                //初始化
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (!Field.IsExist(list, fieldname)) { throw new Exception("Invalid fieldname: " + fieldname); }

                if (wssIds != null && wssIds.Count > 0)
                {
                    //CAML Query
                    SPQuery q = new SPQuery();
                    q.Query = "<Where><In><FieldRef Name='" + fieldname + "' LookupId='TRUE' /><Values>";
                    foreach (int wssId in wssIds)
                    {
                        q.Query += "<Value Type='Integer'>" + wssId + "</Value>";
                    }
                    q.Query += "</Values></In></Where>";

                    //字段
                    if (fieldsToReturn != null && fieldsToReturn.Length > 0)
                    {
                        q.ViewFields = Caml.FormatSPQueryViewFields(fieldsToReturn);
                    }

                    //排序
                    if (orderByFields != null && orderByFields.Count > 0)
                    {
                        q.Query += Caml.FormatOrderBy(orderByFields);
                    }

                    //获取
                    items = list.GetItems(q);
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("6e5r7tydrhgxdfddxgdgdgx", ex);
            }
            return items;
        }
        #endregion

        #region 获取匹配多个termId的item的集合
        /// <summary>
		/// 获取匹配多个termId的item的集合
		/// </summary>
		/// <param name="list"></param>
		/// <param name="fieldname"></param>
		/// <param name="termIds"></param>
		/// <param name="fieldsToReturn"></param>
		/// <param name="orderByFields"></param>
		/// <returns></returns>
		public static SPListItemCollection GetItemsByTerms(SPList list, string fieldname, List<Guid> termIds,
            string[] fieldsToReturn, List<Caml.OrderByField> orderByFields)
        {
            try
            {
                //获取wssIds
                SPWeb rootWeb = null;
                if (SPContext.Current != null && SPContext.Current.Site != null)
                {
                    rootWeb = SPContext.Current.Site.RootWeb;
                }
                else if (list != null && list.ParentWeb != null && list.ParentWeb.Site != null)
                {
                    rootWeb = list.ParentWeb.Site.RootWeb;
                }
                var wssIds = Taxonomy.GetWssIds(rootWeb, termIds);


                // 执行
                return GetItemsByTerms(list, fieldname, wssIds, fieldsToReturn, orderByFields);
            }
            catch (Exception ex)
            {
                Log.WriteError("6e5eryhdsfxcvsZdfxghcffcjcg", ex);
                return null;
            }
        }
        #endregion

        #region 获取匹配指定taxonomy field value的item集合
        /// <summary>
        /// 获取匹配指定taxonomy field value的item集合
		/// </summary>
		/// <param name="list"></param>
		/// <param name="fieldname"></param>
		/// <param name="taxonomyFieldValue"></param>
		/// <param name="fieldsToReturn"></param>
		/// <param name="orderByFields"></param>
		/// <returns></returns>
		public static SPListItemCollection GetItemsByTerms(SPList list, string fieldname,
            ICollection<TaxonomyFieldValue> taxonomyFieldValue, string[] fieldsToReturn,
            List<Caml.OrderByField> orderByFields)
        {
            if (taxonomyFieldValue != null)
            {
                var wssIds = new List<int>();
                foreach (TaxonomyFieldValue t in taxonomyFieldValue)
                {
                    wssIds.Add(t.WssId);
                }

                // 执行
                return GetItemsByTerms(list, fieldname, wssIds, fieldsToReturn, orderByFields);
            }
            return null;
        }
        #endregion

        #region 根据lookup field的值所在的联级的list的item ID来获取匹配的item集合
        /// <summary>
		/// 根据lookup field的值所在的联级的list的item ID来获取匹配的item集合
		/// </summary>
		/// <param name="list"></param>
		/// <param name="lookupFieldname"></param>
		/// <param name="lookupFieldIds"></param>
		/// <param name="fieldsToReturn"></param>
		/// <param name="orderByFields"></param>
		/// <returns></returns>
		public static SPListItemCollection GetItemsByLookupField(SPList list, string lookupFieldname, List<int> lookupFieldIds,
            string[] fieldsToReturn, List<Caml.OrderByField> orderByFields)
        {
            SPListItemCollection items = null;
            try
            {
                // init
                if (list == null) { throw new Exception("SPList passed is null"); }
                if (!Field.IsExist(list, lookupFieldname)) { throw new Exception("Invalid fieldname: " + lookupFieldname); }

                if (lookupFieldIds != null && lookupFieldIds.Count > 0)
                {
                    // CAML query
                    SPQuery q = new SPQuery();
                    q.Query = "<Where><In><FieldRef Name='" + lookupFieldname + "' LookupId='TRUE' /><Values>";
                    foreach (int id in lookupFieldIds)
                    {
                        q.Query += "<Value Type='Integer'>" + id + "</Value>";
                    }
                    q.Query += "</Values></In></Where>";

                    // fields
                    if (fieldsToReturn != null && fieldsToReturn.Length > 0)
                    {
                        q.ViewFields = Caml.FormatSPQueryViewFields(fieldsToReturn);
                    }

                    // 排序
                    if (orderByFields != null && orderByFields.Count > 0)
                    {
                        q.Query += Caml.FormatOrderBy(orderByFields);
                    }

                    // 获取
                    items = list.GetItems(q);
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("e56jygtdrhsreersers", ex);
            }
            return items;
        }
        #endregion

        #region 保存一个item
        /// <summary>
		/// 保存一个item
		/// </summary>
		/// <param name="item"></param>
		/// <returns></returns>
		public static bool Save(SPListItem item)
        {

            bool isSuccess = false;
            try
            {
                if (item == null) { throw new Exception("SPListItem passed is null"); }
                List<SPListItem> itemsToSave = new List<SPListItem>(); itemsToSave.Add(item);
                List<SPListItem> itemsFailedToSave = new List<SPListItem>();
                Save(itemsToSave, false, ref itemsFailedToSave);

                if (itemsFailedToSave.Count > 0) { isSuccess = false; }
                else { isSuccess = true; }
            }
            catch (Exception ex)
            {
                string title = item == null ? "Null SPListItem" : item.Title;
                Log.WriteError("re65tyfdtrsreestsgdrstrtt", ex, "SPListItem.Title: " + title);
                isSuccess = false;
            }
            return isSuccess;
        }
        #endregion

        #region 保存多个item，只要其中一个失败，则返回false
        /// <summary>
		/// 保存多个item，只要其中一个失败，则返回false
		/// </summary>
		/// <param name="items"></param>
		/// <returns></returns>
		public static bool Save(List<SPListItem> items)
        {
            bool isSuccess = false;
            try
            {
                List<SPListItem> itemsFailedToSave = new List<SPListItem>();
                Save(items, false, ref itemsFailedToSave);

                if (itemsFailedToSave.Count > 0) { isSuccess = false; }
                else { isSuccess = true; }

            }
            catch (Exception ex)
            {
                Log.WriteError("6ur8ykguffdseer", ex);
                isSuccess = false;
            }
            return isSuccess;
        }
        #endregion

        #region 保存多个item
        /// <summary>
		/// 保存多个item
		/// </summary>
		/// <param name="itemsToSave"></param>
		/// <param name="itemsFailedToSave"></param>
		public static void Save(List<SPListItem> itemsToSave, bool isRemoveItemsFailedToSave,
            ref List<SPListItem> itemsFailedToSave)
        {
            string currentItem = null;
            try
            {
                if (itemsToSave == null) { throw new Exception("Passed an empty collection of SPListItems"); }

                if (itemsToSave.Count > 0)
                {
                    foreach (SPListItem item in itemsToSave)
                    {
                        currentItem = item.Name;
                        try
                        {
                            item.Update();
                        }
                        catch (Exception ex)
                        {
                            if (itemsFailedToSave == null) { itemsFailedToSave = new List<SPListItem>(); }
                            itemsFailedToSave.Add(item);
                            Log.WriteError("dtrufgdstyrerse5", "Failed to save item: " + currentItem + ". Error: " + ex.Message + " \n\n\n" + ex.ToString());
                        }
                    }

                    // 移除保存失败的document
                    if (isRemoveItemsFailedToSave && itemsFailedToSave != null && itemsFailedToSave.Count > 0)
                    {
                        for (int i = 0; i < itemsToSave.Count; i++)
                        {
                            bool isMatch = false;
                            foreach (SPListItem item in itemsFailedToSave)
                            {
                                if (itemsToSave[i] == item)
                                {
                                    isMatch = true;
                                    break;
                                }
                            }
                            if (isMatch)
                            {
                                itemsToSave.RemoveAt(i);
                                i--;
                            }
                        }
                    } //移除保存失败的item
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("t7rrjtcxgfbcxffxd", ex, "current item: " + currentItem);
            }
        }
        #endregion

        #region 大批量删除item
        /// <summary>
		/// 大批量删除item
		/// 不会删除checked out的items
        /// 不会删除Pages library中的homepage 
		/// http://msdn.microsoft.com/en-us/library/ms461938.aspx
		/// http://social.technet.microsoft.com/Forums/en-US/sharepoint2010customization/thread/e0eefd6b-e954-46d8-9c49-703de6eda592
		/// </summary>
		/// <param name="list">要删除的item集合所在的list</param>
		/// <param name="isDisableRecycleBin">如果是false，那么回收站里面的也会被删除</param>
		/// <returns></returns>
		public static bool BulkDeleteItems(SPList list, SPListItemCollection items, bool isDisableRecycleBin)
        {
            bool isSuccess = true;
            try
            {
                // 初始化
                if (list == null) { throw new Exception("SPlist passed is null"); }
                if (items == null) { throw new Exception("SPLitItems collection passed is null"); }

                if (items.Count > 0)
                {
                    // WAKAKA！！！这也会删除回收站里的所有item
                    if (isDisableRecycleBin && list.ParentWeb.Site.WebApplication.RecycleBinEnabled)
                    { list.ParentWeb.Site.WebApplication.RecycleBinEnabled = false; }
                    list.ParentWeb.AllowUnsafeUpdates = true;

                    string deleteCamlQuery = null;
                    string camlStart = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Batch>";
                    string camlEnd = "</Batch>";
                    string command = "<Method><SetList Scope=\"Request\">" + list.ID + "</SetList>"
                        + "<SetVar Name=\"ID\">{0}</SetVar>"
                        + "<SetVar Name=\"Cmd\">Delete</SetVar>";
                    if (list.BaseType == SPBaseType.DocumentLibrary)
                    {
                        // 对于document libraries, 需要额外的 owsfileref 参数
                        command += "<SetVar Name=\"owsfileref\">{1}</SetVar>";
                    }
                    command += "</Method>";

                    int numberItemsToBatchDelete = 0;
                    for (int i = (items.Count - 1); i > -1; i--)
                    {
                        if (list.BaseType == SPBaseType.DocumentLibrary)
                        {
                            // 格式化删除文件的命令
                            deleteCamlQuery += string.Format(command, items[i].ID.ToString(), items[i].File.ServerRelativeUrl);
                        }
                        else
                        {
                            // 格式化删除item的命令
                            deleteCamlQuery += string.Format(command, items[i].ID.ToString());
                        }
                        numberItemsToBatchDelete++;

                        //删除一批(一批100个，或者最后一个)
                        if (numberItemsToBatchDelete > 99 || i == 0)
                        {
                            deleteCamlQuery = camlStart + deleteCamlQuery + camlEnd;
                            var results = list.ParentWeb.ProcessBatchData(deleteCamlQuery);

                            // 检查是否有错误返回
                            if (results.Contains("<ErrorText>")) { isSuccess = false; }

                            // 删除成功，重新设置每一批的索引以及清空CAML
                            deleteCamlQuery = null;
                            numberItemsToBatchDelete = 0;
                        }
                    }
                } // 如果还有item
            }
            catch (Exception ex)
            {
                Log.WriteError("iukyufydtrt65tyrtdgdsffdr", ex);
                isSuccess = false;
            }
            finally
            {
                // 重新enable回收站
                if (isDisableRecycleBin && list != null && !list.ParentWeb.Site.WebApplication.RecycleBinEnabled)
                { list.ParentWeb.Site.WebApplication.RecycleBinEnabled = true; }
                list.ParentWeb.AllowUnsafeUpdates = false;
            }
            return isSuccess;
        }
        #endregion

        #region 使用批量删除来清空指定的list
        /// <summary>
		/// 使用批量删除来清空指定的list
        /// 不会删除checked out的items,不会删除Pages library中的homepage 
		/// </summary>
		/// <param name="list"></param>
		/// <param name="isDisableRecycleBin"></param>
		/// <returns></returns>
		public static bool DeleteAllItems(SPList list, bool isDisableRecycleBin)
        {
            bool isSuccess = false;
            try
            {
                if (list == null) { throw new Exception("SPList passed is null"); }
                isSuccess = BulkDeleteItems(list, list.Items, isDisableRecycleBin);
            }
            catch (Exception ex)
            {
                Log.WriteError("78ti6ry5esrggsdgssgr", ex);
                isSuccess = false;
            }
            return isSuccess;
        }
        #endregion       

        #region 获取某个item的attachment集合
        /// <summary>
		/// 获取某个item的attachment集合
		/// http://www.binarywave.com/blogs/eshupps/Lists/Posts/Post.aspx?List=89cbe813-99f7-4257-a23a-5fefc377336b&ID=26&Web=c7893495-be3b-4d73-9875-28b039760651
		/// </summary>
		/// <param name="item"></param>
		public static SPFileCollection GetAttachments(SPListItem item)
        {
            SPFileCollection files = null;
            try
            {
                // init
                if (item == null) { throw new Exception("SPListItem passed is null"); }
                if (item.ParentList == null || item.ParentList.RootFolder == null) { throw new Exception("SPListItem passed does not have SPList prefetched"); }


                SPFolder folder = item.ParentList.RootFolder.SubFolders["Attachments"].SubFolders[item.ID.ToString()];
                if (folder != null && folder.Files != null) { files = folder.Files; }
            }
            catch (Exception ex)
            {
                Log.WriteError("srydytidruseyey", ex);
                files = null;
            }
            return files;
        }
        #endregion

        #region 根据list item获取其attachment的名字集合
        /// <summary>
		/// 根据list item获取其attachment的名字集合
		/// </summary>
		/// <param name="item"></param>
		/// <returns></returns>
		public static List<string> GetAttachmentFilenames(SPListItem item)
        {
            List<string> filenames = null;
            try
            {
                // 初始化
                if (item == null) { throw new Exception("SPListItem passed is null"); }
                filenames = new List<string>();

                if (item.Attachments != null && item.Attachments.Count > 0)
                {
                    foreach (string filename in item.Attachments)
                    {
                        filenames.Add(filename);
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("sdtrygfydtsuersruxgf6rgcf", ex);
                filenames = null;
            }
            return filenames;
        }
        #endregion

        #region 根据list item获取其attachment的url集合
        /// <summary>
        /// 根据list item获取其attachment的url集合
		/// </summary>
		/// <param name="item"></param>
		/// <returns></returns>
		public static List<string> GetAttachmentUrls(SPListItem item)
        {
            List<string> urls = null;
            try
            {
                // 初始化
                if (item == null) { throw new Exception("SPListItem passed is null"); }
                urls = new List<string>();

                if (item.Attachments != null && item.Attachments.Count > 0)
                {
                    foreach (string filename in item.Attachments)
                    {
                        urls.Add(item.Attachments.UrlPrefix + filename);
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("6e5idjthssdrrdst", ex);
                urls = null;
            }
            return urls;
        }
        #endregion

        #region 根据list item获取其attachment的集合
        /// <summary>
        /// 根据list item获取其attachment的集合
		/// </summary>
		/// <param name="item"></param>
		/// <returns></returns>
		public static List<SPFile> GetAttachmentFiles(SPListItem item)
        {
            List<SPFile> attachments = null;
            try
            {
                // 初始化
                if (item == null) { throw new Exception("SPListItem passed is null"); }
                attachments = new List<SPFile>();

                if (item.Attachments != null && item.Attachments.Count > 0)
                {
                    foreach (string filename in item.Attachments)
                    {
                        attachments.Add(item.Web.GetFile(item.Attachments.UrlPrefix + filename));
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("rs6yu5rhseerssrt", ex);
                attachments = null;
            }
            return attachments;
        }
        #endregion

        #region 系统默认list集合
        /// <summary>
		/// 系统默认list集合
		/// </summary>
		public static List<string> RecentChangesSystemListsToExclude
        {
            get
            {
                return new List<string>()
                {
                    { "Content and Structure Reports" },
                    { "Customized Reports" },
                    { "Form Templates" },
                    { "Reusable Content" },
                    { "Site Assets" },
                    { "Site Collection Images" },
                    { "Style Library" },
                    { "Whereabouts" }
                };
            }
        }
        #endregion

        #region 获取某个list最近创建/修改的item集合
        /// <summary>
		/// 获取某个list最近创建/修改的item集合
		/// </summary>
		/// <param name="list"></param>
		/// <param name="contentTypesToInclude">如果是null，则搜索所有content type，如果不为null，则搜索指定的content type</param>
		/// <param name="contentTypesToExclude">这些content type将会被排除</param>
		/// <param name="itemMinimumDate">如果是null，则会获取所有</param>
		/// <returns></returns>
		public static List<SPListItem> RecentChanges(SPList list, string[] contentTypesToInclude, string[] contentTypesToExclude, DateTime? itemMinimumDate)
        {
            string currentListUrl = null;
            string currentItemUrl = null;
            List<SPListItem> items = null;
            try
            {
                // 初始化
                if (list == null) { throw new Exception("SPList passed is null"); }
                currentListUrl = List.GetUrl(list);
                items = new List<SPListItem>();


                // 获取list items
                foreach (SPListItem item in list.Items)
                {
                    currentItemUrl = item.Url;
                    if (isIncludeItem(item, contentTypesToInclude, contentTypesToExclude, itemMinimumDate))
                    {
                        items.Add(item);
                    }
                    currentItemUrl = null;
                }

                // 获取 list folders
                if (list.Folders != null)
                {
                    foreach (SPListItem folder in list.Folders)
                    {
                        currentItemUrl = folder.Url;
                        if (isIncludeItem(folder, contentTypesToInclude, contentTypesToExclude, itemMinimumDate))
                        {
                            items.Add(folder);
                        }
                        currentItemUrl = null;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("8yigfrftsdeddfyuttf", ex,
                    "list url: " + currentListUrl + ", item url: " + currentItemUrl);
                items = null;
            }
            return items;
        }
        #endregion

        #region 获取某个web下最近更改的list item集合
        /// <summary>
		/// 获取某个web下最近更改的list item集合
		/// </summary>
		/// <param name="web"></param>
		/// <param name="listsToInclude"></param>
		/// <param name="listsToExclude"></param>
		/// <param name="listBaseTemplatesToExclude">需要排除的list模板, 比如 "Tasks", "Events", etc.</param>
		/// /// <param name="listBaseTemplatesToInclude">需要包含的list模板, 比如 "Tasks", "Events", etc.</param>
		/// <param name="contentTypesToExclude">需要包含的Content Type, 比如 "Item" "Calendar" "Task"</param>
		/// <param name="itemMinimumDate">修改的最早deadline日期</param>
		/// <returns></returns>
		public static List<SPListItem> RecentChanges(SPWeb web, bool isIncludeChildWebs, string[] listsToInclude, string[] listsToExclude,
            string[] listBaseTemplatesToInclude, string[] listBaseTemplatesToExclude,
            string[] contentTypesToInclude, string[] contentTypesToExclude, DateTime? itemMinimumDate)
        {
            string currentWebUrl = null;
            string currentListUrl = null;
            List<SPListItem> items = null;
            try
            {
                // 初始化
                if (web == null) { throw new Exception("SPWeb passed is null"); }
                currentWebUrl = web.Url;
                items = new List<SPListItem>();


                foreach (SPList list in web.Lists)
                {
                    currentListUrl = list.DefaultViewUrl;

                    // 判断这个list是否被包含
                    bool isIncludeList = true;

                    ////////////////////////////////////////////////////////////////////////////////////
                    // 默认隐藏被排除的列表
                    if (list.Hidden) { isIncludeList = false; }

                    ////////////////////////////////////////////////////////////////////////////////////
                    // 包含的list的title
                    if (!isIncludeList && listsToInclude != null && listsToInclude.Length > 0)
                    {
                        isIncludeList = false;
                        foreach (string listTitle in listsToInclude)
                        {
                            if (listTitle.ToLower().Trim() == list.Title.ToLower().Trim())
                            {
                                isIncludeList = true;
                                break;
                            }
                        }
                    }

                    ////////////////////////////////////////////////////////////////////////////////////
                    // 排除的list的title
                    if (isIncludeList && listsToExclude != null && listsToExclude.Length > 0)
                    {
                        foreach (string listTitle in listsToExclude)
                        {
                            if (listTitle.ToLower().Trim() == list.Title.ToLower().Trim())
                            {
                                isIncludeList = false;
                                break;
                            }
                        }
                    }

                    ////////////////////////////////////////////////////////////////////////////////////
                    // 包含的list的template
                    if (!isIncludeList && listBaseTemplatesToInclude != null && listBaseTemplatesToInclude.Length > 0)
                    {
                        isIncludeList = false;
                        string listBaseTemplate = list.BaseTemplate.ToString().ToLower().Trim();
                        foreach (string listBaseTemplateToInclude in listBaseTemplatesToInclude)
                        {
                            if (listBaseTemplateToInclude.ToLower().Trim() == listBaseTemplate)
                            {
                                isIncludeList = true;
                                break;
                            }
                        }
                    }

                    ////////////////////////////////////////////////////////////////////////////////////
                    // 排除的list的template
                    if (isIncludeList && listBaseTemplatesToExclude != null && listBaseTemplatesToExclude.Length > 0)
                    {
                        string listBaseTemplate = list.BaseTemplate.ToString().ToLower().Trim();
                        foreach (string listBaseTemplateToExclude in listBaseTemplatesToExclude)
                        {
                            if (listBaseTemplateToExclude.ToLower().Trim() == listBaseTemplate)
                            {
                                isIncludeList = false;
                                break;
                            }
                        }
                    }


                    // 扫描修改的list
                    if (isIncludeList)
                    {
                        List<SPListItem> _items = RecentChanges(list, contentTypesToInclude, contentTypesToExclude, itemMinimumDate);
                        if (_items != null && _items.Count > 0) { items.AddRange(_items); }
                    }

                    currentListUrl = null;
                } // 遍历list


                // 子站点?
                if (isIncludeChildWebs && web.Webs.Count > 0)
                {
                    foreach (SPWeb childWeb in web.Webs)
                    {
                        // 调用
                        List<SPListItem> childItems = RecentChanges(childWeb, isIncludeChildWebs, listsToInclude, listsToExclude,
                            listBaseTemplatesToInclude, listBaseTemplatesToExclude,
                            contentTypesToInclude, contentTypesToExclude, itemMinimumDate);
                        if (childItems == null) { Log.WriteError("u6r7i6tytfdrstdsrt", "Failed to get child items for childWeb: " + childWeb.Url); }

                        // 添加到主list
                        if (childItems != null && childItems.Count > 0) { items.AddRange(childItems); }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("6ui7yuytsdeddfyuttf", ex,
                    "web url: " + currentWebUrl + ", list url: " + currentListUrl);
                items = null;
            }
            return items;
        }
        #endregion

        #region filter 用于判断某个item最近是不是发生了修改
        /// <summary>
		/// filter 用于判断某个item最近是不是发生了修改
		/// </summary>
		/// <param name="item"></param>
		/// <param name="contentTypesToInclude"></param>
		/// <param name="contentTypesToExclude"></param>
		/// <param name="itemMinimumDate"></param>
		/// <returns></returns>
		public static bool isIncludeItem(SPListItem item, string[] contentTypesToInclude, string[] contentTypesToExclude,
            DateTime? itemMinimumDate)
        {
            bool _isIncludeItem = true;
            if (item == null) { _isIncludeItem = false; }
            else
            {
                // content type
                if ((contentTypesToInclude != null && contentTypesToInclude.Length > 0) ||
                    (contentTypesToExclude != null && contentTypesToExclude.Length > 0)
                    )
                {
                    string contentTypeName = ContentType.GetContentTypeName(item);
                    if (contentTypesToInclude != null && contentTypesToInclude.Length > 0)
                    {
                        _isIncludeItem = false;
                        foreach (string contentTypetoInclude in contentTypesToInclude)
                        {
                            if (contentTypetoInclude == contentTypeName)
                            {
                                _isIncludeItem = true;
                                break;
                            }
                        }
                    }
                    if (_isIncludeItem && (contentTypesToExclude != null && contentTypesToExclude.Length > 0))
                    {
                        foreach (string contentTypetoExclude in contentTypesToExclude)
                        {
                            if (contentTypetoExclude == contentTypeName)
                            {
                                _isIncludeItem = false;
                                break;
                            }
                        }
                    }
                }

                // 日期 filter
                if (_isIncludeItem && itemMinimumDate != null && itemMinimumDate != DateTime.MinValue)
                {
                    _isIncludeItem = false;
                    DateTime? createdDate = null; DateTime? modifiedDate = null;
                    try
                    {
                        if (item["Created"] != null) { createdDate = item["Created"] as DateTime?; }
                        if (item["Modified"] != null) { modifiedDate = item["Modified"] as DateTime?; }
                    }
                    catch (Exception ex)
                    {
                        string itemUrl = null; if (item != null) { itemUrl = item.Url; }
                        Log.WriteError("6ujdstGGsdgrses", ex, "item url: " + itemUrl);
                    }
                    if ((createdDate != null && createdDate >= itemMinimumDate) ||
                        (modifiedDate != null && modifiedDate >= itemMinimumDate)
                        )
                    {
                        _isIncludeItem = true;
                    }
                }
            }
            return _isIncludeItem;
        }
        #endregion

        #region 获取item的图标URL（相对链接）和项的扩展名。
        /// <summary>
        /// 获取item的图标URL（相对链接）和项的扩展名。
		/// </summary>
		/// <param name="item"></param>
		/// <param name="itemExt"></param>
		/// <returns></returns>
		public static string GetIconUrl(SPListItem item, ref string itemExt)
        {
            string o = null;
            try
            {
                // 初始化
                if (item == null) { throw new Exception("SPListItem passed is null"); }
                string filename = null;


                // 获取item的content type
                string contentTypeName = ContentType.GetContentTypeName(item);

                // 获取item的extenstion
                itemExt = FileEx.GetExtension(item);

                // 获取icon filename
                if (item.File != null) { filename = item.File.IconUrl; }

                if (contentTypeName == "Link")
                {
                    itemExt = "url";
                    filename = "ICHTM.GIF";
                }
                else if (contentTypeName == "Event")
                {
                    itemExt = "Event";
                    filename = "ITEVENT.GIF";
                }
                else if (contentTypeName == "Contact")
                {
                    itemExt = "Contact";
                    filename = "ITCONTCT.GIF";
                }
                else if (contentTypeName == "Message" || contentTypeName == "Discussion")
                {
                    itemExt = "Discussion";
                    filename = "ITDISC.GIF";
                }
                else if (contentTypeName == "Task" || contentTypeName == "Project Task")
                {
                    itemExt = "Task";
                    filename = "ITTASK.PNG";
                }
                else if (contentTypeName == "Issue")
                {
                    itemExt = "Issue";
                    filename = "ITISSUE.PNG";
                }

                // 默认icon的filename
                if (string.IsNullOrEmpty(filename)) { filename = "icgen.gif"; }

                // relative url
                o = "/_layouts/images/" + filename;

            }
            catch (Exception ex)
            {
                Log.WriteError("drstyygiuyufgdtrydrtdtrdfxcf", ex);
                o = null;
            }
            return o;
        }
        #endregion

        #region 获取一个item的 icon Url (相对路径)
        /// <summary>
		/// 获取一个item的 icon Url (相对路径)
		/// </summary>
		/// <param name="item"></param>
		/// <param name="itemExt"></param>
		/// <returns></returns>
		public static string GetIconUrl(SPListItem item)
        {
            string devNull = null;
            // 调用
            return GetIconUrl(item, ref devNull);
        }
        #endregion

        #region 获取 Item url
        /// <summary>
		/// 获取 Item url
		/// </summary>
		/// <param name="item"></param>
        /// <param name="isAbsoluteUrl"></param>
		/// <param name="isUseLinkContentTypeUrlValue"如果是true并且item是相关的内容类型，那么就返回内容类型m的的url</param>
		/// <returns></returns>
		public static string GetUrl(SPListItem item, bool isAbsoluteUrl, bool isUseLinkContentTypeUrlValue)
        {
            string url = null;
            try
            {
                // 初始化
                if (item == null) { throw new Exception("SPListItem passed is null"); }

                // 获取 url， 根据链接的content type的Item?
                string contentTypeName = null;
                if (isUseLinkContentTypeUrlValue) { contentTypeName = ContentType.GetContentTypeName(item); }
                if (isUseLinkContentTypeUrlValue && !string.IsNullOrEmpty(contentTypeName) && contentTypeName == "Link")
                {
                    url = Field.GetUrlOnlyValue(item, "URL");
                    if (string.IsNullOrEmpty(url))
                    {
                        // 获取链接列表的URL
                        url = List.GetUrl(item.ParentList, isAbsoluteUrl);
                    }
                }
                else
                {
                    // 父listurl
                    string parentWebUrl = Web.GetUrl(item.Web, isAbsoluteUrl);
                    if (!string.IsNullOrEmpty(parentWebUrl) && parentWebUrl.Substring(parentWebUrl.Length - 1) == "/")
                    {
                        // 删除尾斜杠
                        parentWebUrl = parentWebUrl.Substring(0, parentWebUrl.Length - 1);
                    }

                    // item url
                    string itemUrl = item.Url;

                    // 更新item URL，如果有一个000扩展，这是一个内部URL或列表项。
                    if (item.File == null ||
                        (!string.IsNullOrEmpty(itemUrl) && itemUrl.Length > 4
                        && itemUrl.Substring(itemUrl.Length - 4) == ".000"))
                    {
                        itemUrl = item.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url + "?ID=" + item.ID;
                    }
                    if (!string.IsNullOrEmpty(itemUrl) && itemUrl.Substring(0, 1) == "/")
                    {
                        // 拆下前斜线，我会稍后添加
                        itemUrl = itemUrl.Substring(1);
                    }

                    // 合并 item url
                    url = parentWebUrl + "/" + itemUrl;

                } // 不是链接item或忽略链接item
            }
            catch (Exception ex)
            {
                Log.WriteError("trztygiyfuyfurHtftrt5", ex);
                url = null;
            }
            return url;
        }

        /// <summary>
        /// 获取 Item url(相对路径)
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string GetUrl(SPListItem item)
        {
            return GetUrl(item, false, false);
        }
        #endregion

        #region 获取item编辑链接，编辑页、item或文件的所有属性。
        /// <summary>
        /// 获取item编辑链接，编辑页、item或文件的所有属性。
        /// (对于一个SPFile，返回文件属性编辑链接，不是编辑文件链接)
		/// </summary>
		/// <param name="item"></param>
		/// <param name="isServerRelativeUrl"></param>
		/// <returns></returns>
		public static string GetEditUrl(SPListItem item, bool isAbsoluteUrl)
        {
            string url = null;
            try
            {
                if (item != null)
                {
                    //父 list url
                    string parentWebUrl = Web.GetUrl(item.Web, isAbsoluteUrl);
                    if (!string.IsNullOrEmpty(parentWebUrl) && parentWebUrl.Substring(parentWebUrl.Length - 1) == "/")
                    {
                        // 删除尾斜杠
                        parentWebUrl = parentWebUrl.Substring(0, parentWebUrl.Length - 1);
                    }

                    // item url
                    string itemUrl = item.ParentList.Forms[PAGETYPE.PAGE_EDITFORM].Url + "?ID=" + item.ID;
                    // 	url += "EditForm.aspx?ID=" + item.ID; 
                    // else { url += "Forms/EditForm.aspx?ID=" + item.ID; }
                    if (!string.IsNullOrEmpty(itemUrl) && itemUrl.Substring(itemUrl.Length - 1) == "/")
                    {
                        // 拆下前斜线
                        itemUrl = itemUrl.Substring(0, itemUrl.Length - 1);
                    }

                    // 合并 with item url
                    url = parentWebUrl + "/" + itemUrl;
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("6uyfhfdfdTHYfdfydfutfu", ex);
            }
            return url;
        }

        /// <summary>
        /// 获取指定的item, page, or file的URL
        /// (对于一个SPFile，返回文件属性编辑链接，不是编辑文件链接)
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string GetEditUrl(SPListItem item)
        {
            // call original
            return GetEditUrl(item, false);
        }
        #endregion

        #region 获取并格式化item的Title. 如果 title==null, 获取 name, 然后 display name, 最后 "(no title)"
        /// <summary>
		/// 获取并格式化item的Title. 如果 title==null, 获取 name, 然后 display name, 最后 "(no title)"
		/// 对于documents, 将获取name
		/// </summary>
		/// <param name="item"></param>
		/// <returns></returns>
		public static string GetTitle(SPListItem item, bool isHttpEncode, int? maxLength)
        {
            string o = null;
            try
            {
                // 初始化
                if (item == null) { throw new Exception("SPListItem passed is null"); }

                // 获取 content type
                string contentTypeName = ContentType.GetContentTypeName(item);

                // 获取 Title (对于documents, 将获取name)
                if (contentTypeName == "Document") { o = item.Name; }
                else
                {
                    try { o = item.Title; } catch { }
                }
                if (string.IsNullOrEmpty(o)) { o = item.Name; }
                if (string.IsNullOrEmpty(o)) { o = item.DisplayName; }
                if (string.IsNullOrEmpty(o)) { o = "(no title)"; }
                if (contentTypeName == "Message") { o = "Reply: " + o; }
                else if (contentTypeName == "Survey") { o = "Survey: " + o; }

                // 是否截断?
                if (maxLength != null)
                {
                    o = Utilities.Truncate(o, (int)maxLength);
                }

                // 是否编码化?
                if (isHttpEncode) { o = System.Web.HttpUtility.HtmlEncode(o); }
            }
            catch (Exception ex)
            {
                Log.WriteError("drttyiHyssdfcvvxfc", ex);
                o = "(no title)";
            }
            return o;
        }

        /// <summary>
        /// 获取并格式化item的Title. 如果 title==null, 获取 name, 然后 display name, 最后 "(no title)"
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string GetTitle(SPListItem item)
        {
            // 调用
            return GetTitle(item, false, null);
        }
        #endregion

        #region copy一个item到目标list
        /// <summary>
		/// copy一个item到目标list
		/// http://www.communardo.de/techblog/2008/01/08/sharepoint-listenelement-splistitem-in-eine-andere-liste-kopieren/
		/// </summary>
		/// <param name="sourceItem"></param>
		/// <param name="destinationList"></param>
		/// <returns></returns>
		public static SPListItem Copy(SPListItem sourceItem, SPList destinationList, ref List<string> failedToCopyFields,
            bool isSave)
        {
            SPListItem destinationItem = null;
            try
            {
                // 初始化
                if (sourceItem == null) { throw new Exception("Source SPListItem passed is null"); }
                if (destinationList == null) { throw new Exception("Destination SPList passed is null"); }
                if (failedToCopyFields == null) { failedToCopyFields = new List<string>(); }


                // 创建目标item
                destinationItem = destinationList.Items.Add();

                // 将属性复制到新item
                foreach (SPField f in sourceItem.Fields)
                {
                    if (!f.ReadOnlyField && f.InternalName != "Attachments")
                    {
                        try
                        {
                            destinationItem[f.InternalName] = sourceItem[f.InternalName];
                        }
                        catch
                        {
                            failedToCopyFields.Add(f.InternalName);
                        }
                    }
                }

                // copy attachments
                if (sourceItem.Attachments != null)
                {
                    foreach (string fileName in sourceItem.Attachments)
                    {
                        try
                        {
                            SPFile file = sourceItem.ParentList.ParentWeb.GetFile(sourceItem.Attachments.UrlPrefix + fileName);
                            byte[] data = file.OpenBinary();
                            destinationItem.Attachments.Add(fileName, data);
                        }
                        catch
                        {
                            failedToCopyFields.Add(sourceItem.Attachments.UrlPrefix + fileName);
                        }
                    }
                }

                // 保存
                if (isSave) { destinationItem.Update(); }
            }
            catch (Exception ex)
            {
                Log.WriteError("vgchhjgfGGgJdgrdst", ex);
                destinationItem = null;
            }
            return destinationItem;
        }
        #endregion

        #region 移除重复的item
        /// <summary>
        /// 移除重复的item
        /// </summary>
        /// <param name="items"></param>
        /// <param name="duplicateItems"></param>
        /// <returns></returns>
        public static List<SPListItem> RemoveDuplicates(SPListItemCollection items, ref List<SPListItem> duplicateItems)
        {
            var itemsNoDups = new List<SPListItem>();
            try
            {
                // 初始化
                if (duplicateItems == null) { duplicateItems = new List<SPListItem>(); }

                // 移除 dups
                if (items != null && items.Count > 0)
                {
                    foreach (SPListItem item in items)
                    {
                        if (!itemsNoDups.Contains(item)) { itemsNoDups.Add(item); }
                        else { duplicateItems.Add(item); }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("65789trdfgdfxgtdtg", ex);
            }
            return itemsNoDups;
        }


        public static List<SPListItem> RemoveDuplicates(SPListItemCollection items)
        {
            var dups = new List<SPListItem>();
            // call original
            return RemoveDuplicates(items, ref dups);
        }

        public static List<SPListItem> RemoveDuplicates(List<SPListItem> items, ref List<SPListItem> duplicateItems)
        {
            var itemsNoDups = new List<SPListItem>();
            try
            {
                // init
                if (duplicateItems == null) { duplicateItems = new List<SPListItem>(); }

                // 移除 dups
                if (items != null && items.Count > 0)
                {
                    foreach (SPListItem item in items)
                    {
                        if (!itemsNoDups.Contains(item)) { itemsNoDups.Add(item); }
                        else { duplicateItems.Add(item); }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("tyihghgfdtfyygugyueer", ex);
            }
            return itemsNoDups;
        }

        public static List<SPListItem> RemoveDuplicates(List<SPListItem> items)
        {
            var dups = new List<SPListItem>();
            // 调用
            return RemoveDuplicates(items, ref dups);
        }
        #endregion

        #region 通过url获取list item
        /// <summary>
		/// 通过url获取list item
		/// </summary>
		/// <param name="url"></param>
		/// <param name="site"></param>
		/// <returns></returns>
		public static SPListItem GetItemByUrl(string url, SPSite site)
        {
            SPListItem item = null;
            try
            {
                // 初始化
                if (string.IsNullOrEmpty(url)) { throw new Exception("Url passed is null"); }
                if (site == null) { site = Site.GetSite(); }
                if (site == null) { throw new Exception("Failed to get SPSite from SPContext"); }


                // 获取 web
                var web = Web.GetWebByUrl(url, site);
                if (web == null) { throw new Exception("Failed to get SPWeb from url"); }

                // 获取 item
                item = web.GetListItem(url);
                if (item == null) { throw new Exception("Failed to get SPListItem from url"); }
            }
            catch (Exception ex)
            {
                Log.WriteError("567807tuyGGfhgddfdfdtr", ex);
                item = null;
            }
            return item;
        }

        /// <summary>
        /// 通过url获取list item
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static SPListItem GetItemByUrl(string url)
        {
            return GetItemByUrl(url, Site.GetSite());
        }
        #endregion

        #region item 格式化
        /// <summary>
        /// 用于HTML格式化item的委托的定义（将Item格式化成类似于这种形式[<li><a href='item url'>item title</a></li>]）
		/// (用于展示多个item)
		/// </summary>
		/// <param name="item"></param>
        /// <returns> 单个SPListItem的HTML格式</returns>
		public delegate string ItemFormatted(SPListItem item);

        /// <summary>
        /// 默认的item格式化的方法
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public static string ItemFormattedDefault(SPListItem item)
        {
            string title = System.Web.HttpUtility.HtmlEncode(Field.GetStringValue(item, "Title"));
            string url = Item.GetUrl(item);
            return string.Format("<li><a href='{0}'>{1}</a></li>", url, title);
        }

        /// <summary>
        /// 委托用来返回item集合group by的key，比如说，根据month group by，那么这个委托就返回这个month number
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public delegate string GroupByKey(SPListItem item);

        /// <summary>
        /// 委托用来返回item集合group by key的value，比如说，根据month group by，那么这个委托就返回这个month的display name
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public delegate string GroupByValue(SPListItem item);

        /// <summary>
        /// 委托用来返回item集合group by的key和value，比如说，根据type group by，那么这个委托就返回所有这个type的集合
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public delegate List<KeyValuePair<string, string>> GroupByKeyValues(SPListItem item);

        /// <summary>
        /// 定义Delegate 返回 group heading, formatted
        /// 比如, 如果通过 month来 grouping , 也许会在 h2 tag返回month name
        /// </summary>
        /// <param name="groupByKeyValue"></param>
        /// <returns>HTML for a group heading</returns>
        public delegate string GroupByHeaderFormatted(string groupByKey, string groupByValue, string listStartTag);

        /*
         *下面是一些具体情况下的方法的使用  
         */
        /// <summary>
        /// Default method for GroupByHeadingFormatted delegate. 
        /// formats group value with anchor bookmark tag, h2 tags, then value
        /// </summary>
        /// <param name="groupByKeyValue"></param>
        /// <returns></returns>
        public static string GroupByHeaderFormattedDefault(string groupByKey, string groupByValue, string listStartTag)
        {
            string value = null;
            if (string.IsNullOrEmpty(groupByValue)) { groupByValue = groupByKey; }
            if (!string.IsNullOrEmpty(groupByKey)) { groupByKey = System.Web.HttpUtility.HtmlEncode(groupByKey); }
            if (!string.IsNullOrEmpty(groupByValue)) { groupByValue = System.Web.HttpUtility.HtmlEncode(groupByValue); }

            if (!string.IsNullOrEmpty(groupByKey)) { value += "<a name='" + groupByKey + "'></a>"; }
            if (!string.IsNullOrEmpty(groupByValue)) { value += "<h2>" + groupByValue + "</h2>"; }
            value += listStartTag;
            return value;
        }

        /// <summary>
        /// Delegate returns group footer, formatted
        /// useful for when you want to add a 'More Link' at bottom of the group of items
        /// </summary>
        /// <param name="groupByKeyValue"></param>
        /// <returns></returns>
        public delegate string GroupByFooterFormatted(string groupByKey, string groupByValue, string listEndTag);
        public static string GroupByFooterFormattedDefault(string groupByKey, string groupByValue, string listEndTag)
        {
            return listEndTag;
        }

        public static string DisplayItems(SPListItemCollection items, ItemFormatted itemFormatted)
        {
            var itemsList = ConvertSPListItemCollectionToGenericCollection(items);

            var devNull = new List<KeyValuePair<string, string>>();
            return displayItems(itemsList, itemFormatted, delegate { return null; }, delegate { return null; },
                delegate { return null; }, false, false,
                delegate { return null; }, null,
                delegate { return null; }, null,
                ref devNull);
        }

        public static string DisplayItems(SPListItemCollection items, ItemFormatted itemFormatted,
            string headerHtml, string footerHtml)
        {
            var itemsList = ConvertSPListItemCollectionToGenericCollection(items);

            var devNull = new List<KeyValuePair<string, string>>();

            return displayItems(itemsList, itemFormatted, delegate { return null; }, delegate { return null; },
                delegate { return null; }, false, false,
                delegate { return headerHtml; }, null,
                delegate { return footerHtml; }, null,
                ref devNull);
        }

        public static string DisplayItems(List<SPListItem> items, ItemFormatted itemFormatted,
            string headerHtml, string footerHtml)
        {
            var devNull = new List<KeyValuePair<string, string>>();
            return displayItems(items, itemFormatted, delegate { return null; }, delegate { return null; },
                delegate { return null; }, false, false,
                delegate { return headerHtml; }, null,
                delegate { return footerHtml; }, null, ref devNull);
        }

        public static string DisplayItems(SPListItemCollection items, ItemFormatted itemFormatted,
            GroupByHeaderFormatted headerFormatted, GroupByFooterFormatted footerFormatted)
        {
            var itemsList = ConvertSPListItemCollectionToGenericCollection(items);

            var devNull = new List<KeyValuePair<string, string>>();
            return displayItems(itemsList, itemFormatted, delegate { return null; }, delegate { return null; },
                delegate { return null; }, false, false,
                headerFormatted, null,
                footerFormatted, null,
                ref devNull);
        }

        public static string DisplayItems(List<SPListItem> items, ItemFormatted itemFormatted,
            GroupByHeaderFormatted headerFormatted, GroupByFooterFormatted footerFormatted)
        {
            var devNull = new List<KeyValuePair<string, string>>();
            return displayItems(items, itemFormatted, delegate { return null; }, delegate { return null; },
                delegate { return null; }, false, false,
                headerFormatted, null,
                footerFormatted, null,
                ref devNull);
        }



        public static string DisplayItemsGrouped(SPListItemCollection items, ItemFormatted itemFormatted,
            GroupByKey groupByKey, GroupByValue groupByValue, bool isReOrderItemsByGroup,
            GroupByHeaderFormatted groupByHeaderFormatted, string listStartTag,
            GroupByFooterFormatted groupByFooterFormatted, string listEndTag,
            ref List<KeyValuePair<string, string>> groupByKeyValuesUsed)
        {
            var itemsList = ConvertSPListItemCollectionToGenericCollection(items);

            return displayItems(itemsList, itemFormatted, groupByKey, groupByValue, delegate { return null; },
                isReOrderItemsByGroup, false,
                groupByHeaderFormatted, listStartTag, groupByFooterFormatted, listEndTag,
                ref groupByKeyValuesUsed);
        }

        public static string DisplayItemsGrouped(SPListItemCollection items, ItemFormatted itemFormatted,
            GroupByKey groupByKey, GroupByValue groupByValue, bool isReOrderItemsByGroup,
            string headerHtml, string footerHtml,
            ref List<KeyValuePair<string, string>> groupByKeyValuesUsed)
        {
            var itemsList = ConvertSPListItemCollectionToGenericCollection(items);

            return displayItems(itemsList, itemFormatted, groupByKey, groupByValue, delegate { return null; },
                isReOrderItemsByGroup, false, GroupByHeaderFormattedDefault, headerHtml,
                GroupByFooterFormattedDefault, footerHtml, ref groupByKeyValuesUsed);
        }

        public static string DisplayItemsGroupedByKeyValues(SPListItemCollection items, ItemFormatted itemFormatted,
            GroupByKeyValues groupByKeyValues, bool isReOrderItemsByGroup,
            GroupByHeaderFormatted groupByHeaderFormatted, string listStartTag,
            GroupByFooterFormatted groupByFooterFormatted, string listEndTag,
            ref List<KeyValuePair<string, string>> groupByKeyValuesUsed)
        {
            var itemsList = ConvertSPListItemCollectionToGenericCollection(items);

            return displayItems(itemsList, itemFormatted, delegate { return null; }, delegate { return null; },
                groupByKeyValues, isReOrderItemsByGroup, true,
                groupByHeaderFormatted, listStartTag,
                groupByFooterFormatted, listEndTag,
                ref groupByKeyValuesUsed);
        }

        public static string DisplayItemsGroupedByKeyValues(SPListItemCollection items, ItemFormatted itemFormatted,
            GroupByKeyValues groupByKeyValues, bool isReOrderItemsByGroup,
            string headerHtml, string footerHtml,
            ref List<KeyValuePair<string, string>> groupByKeyValuesUsed)
        {
            var itemsList = ConvertSPListItemCollectionToGenericCollection(items);

            return displayItems(itemsList, itemFormatted, delegate { return null; }, delegate { return null; },
                groupByKeyValues, isReOrderItemsByGroup, true,
                GroupByHeaderFormattedDefault, headerHtml,
                GroupByFooterFormattedDefault, footerHtml,
                ref groupByKeyValuesUsed);
        }

        /// <summary>
        /// 展示一组item, grouped by date
        /// 默认, 以 'Month, day year'排序. To group by Month, pass "MMMM", to group by year, pass "yyyy"
        /// </summary>
        /// <param name="items"></param>
        /// <param name="itemFormatted">Delegate to format each item w/ HTML</param>
        /// <param name="dateTimeFieldInternalName">This is the field to get the date value from</param>
        /// <param name="groupByDateFormatString">Default is "MMMM d, yyyy"</param>
        /// <param name="unorderedListParameters">This can include class and inline styles that will be added to ul tag</param>
        /// <param name="groupByKeyValuesUsed">List of group by values that were found in the items passed</param>
        /// <returns></returns>
        public static string DisplayItemsGroupedByDate(SPListItemCollection items, ItemFormatted itemFormatted,
            string dateTimeFieldInternalName, string groupByDateFormatString,
            GroupByHeaderFormatted groupByHeaderFormatted, string listStartTag,
            GroupByFooterFormatted groupByFooterFormatted, string listEndTag,
            ref List<KeyValuePair<string, string>> groupByKeyValuesUsed)
        {
            string o = null;
            try
            {
                // 初始化
                if (string.IsNullOrEmpty(dateTimeFieldInternalName)) { dateTimeFieldInternalName = "Modified"; }
                if (string.IsNullOrEmpty(groupByDateFormatString)) { groupByDateFormatString = "MMMM d, yyyy"; }


                GroupByKey groupByKey = delegate (SPListItem item)
                {
                    var dateTime = Field.GetDateTimeValue(item, dateTimeFieldInternalName);
                    if (dateTime != null)
                    {
                        return dateTime.Value.ToString(groupByDateFormatString);
                    }
                    else { return null; }
                };

                o = DisplayItemsGrouped(items, itemFormatted, groupByKey, delegate { return null; }, false,
                    groupByHeaderFormatted, listStartTag,
                    groupByFooterFormatted, listEndTag,
                    ref groupByKeyValuesUsed);
            }
            catch (Exception ex)
            {
                Log.WriteError("ertryuydsdstsdtr", ex);
                o = null;
            }
            return o;
        }

        /// <summary>
        /// 展示一组item, grouped by date
        /// 默认, 以 'Month, day year'排序. To group by Month, pass "MMMM", to group by year, pass "yyyy"
        /// </summary>
        /// <param name="items"></param>
        /// <param name="itemFormatted">Delegate to format each item w/ HTML</param>
        /// <param name="dateTimeFieldInternalName">This is the field to get the date value from</param>
        /// <param name="groupByDateFormatString">Default is "MMMM d, yyyy"</param>
        /// <param name="listStartTag">This can include class and inline styles that will be added to ul tag</param>
        /// <param name="listEndTag">This is the tag that ends a list</param>
        /// <param name="groupByKeyValuesUsed">List of group by values that were found in the items passed</param>
        /// <returns></returns>
        public static string DisplayItemsGroupedByDate(SPListItemCollection items, ItemFormatted itemFormatted,
            string dateTimeFieldInternalName, string groupByDateFormatString, string listStartTag, string listEndTag,
            ref List<KeyValuePair<string, string>> groupByKeyValuesUsed)
        {
            if (string.IsNullOrEmpty(dateTimeFieldInternalName)) { dateTimeFieldInternalName = "Modified"; }
            if (string.IsNullOrEmpty(groupByDateFormatString)) { groupByDateFormatString = "MMMM d, yyyy"; }

            GroupByKey groupByKey = delegate (SPListItem item)
            {
                var dateTime = Field.GetDateTimeValue(item, dateTimeFieldInternalName);
                if (dateTime != null)
                {
                    return dateTime.Value.ToString(groupByDateFormatString);
                }
                else { return null; }
            };

            return displayItems(ConvertSPListItemCollectionToGenericCollection(items), itemFormatted, groupByKey,
                delegate { return null; }, delegate { return null; }, false, false,
                GroupByHeaderFormattedDefault, listStartTag,
                GroupByFooterFormattedDefault, listEndTag,
                ref groupByKeyValuesUsed);
        }

        /// <summary>
        /// Display a list of SPListItems
        /// </summary>
        /// <param name="items"></param>
        /// <param name="itemFormatted">delegate to return each individual item in html format</param>
        /// <param name="groupByKeyValue">delegate to return the key value pair to group by</param>
        /// <param name="groupByHeaderFormatted">delegate to return the group header formatted</param>
        /// <param name="groupByFooterFormatted">delegate to return the group footer formatted, useful for 'More Link'</param>
        /// <param name="unorderedListParameters">This can include class and inline styles that will be added to ul tag</param>
        /// <param name="groupByKeyValuesUsed">List of group by values that were found in the items passed</param>
        /// <returns></returns>
        private static string displayItems(List<SPListItem> items, ItemFormatted itemFormatted,
            GroupByKey groupByKey, GroupByValue groupByValue, GroupByKeyValues groupByKeyValues,
            bool isReOrderItemsByGroup, bool isItemsUnderMoreThanOneGroup,
            GroupByHeaderFormatted groupByHeaderFormatted, string listStartTag,
            GroupByFooterFormatted groupByFooterFormatted, string listEndTag,
            ref List<KeyValuePair<string, string>> groupByKeyValuesUsed)
        {
            string o = null;
            try
            {
                // init
                if (items == null) { throw new Exception("SPListItems collection passed is null"); }
                if (groupByKeyValuesUsed == null) { groupByKeyValuesUsed = new List<KeyValuePair<string, string>>(); }


                string previousGroupKey = null;
                string previousGroupValue = null;
                string currentGroupKey = null;
                string currentGroupValue = null;
                bool isFirstItem = true;
                bool isFooterNeeded = false;

                // reorder for grouping?
                var groupByKeyValuesUsedAfterReorder = new Dictionary<int, KeyValuePair<string, string>>();
                if (items != null && items.Count > 0 && isReOrderItemsByGroup)
                {
                    var devNull = new List<string>();
                    items = reOrderItemsByGroup(items, isItemsUnderMoreThanOneGroup,
                        groupByKey, groupByValue, groupByKeyValues, ref groupByKeyValuesUsedAfterReorder);
                }

                foreach (SPListItem item in items)
                {
                    ///////////////////////////////////////////////////////////
                    // GROUP

                    // get current item's group key and display name
                    currentGroupKey = null;
                    currentGroupValue = null;
                    if (isReOrderItemsByGroup)
                    {
                        if (groupByKeyValuesUsedAfterReorder.ContainsKey(item.ID))
                        {
                            currentGroupKey = groupByKeyValuesUsedAfterReorder[item.ID].Key;
                            currentGroupValue = groupByKeyValuesUsedAfterReorder[item.ID].Value;
                        }
                    }
                    else
                    {
                        currentGroupKey = groupByKey(item);
                        currentGroupValue = groupByValue(item);
                    }

                    // new group
                    if (currentGroupKey != previousGroupKey || isFirstItem)
                    {
                        // end previous group if not first element
                        if (!isFirstItem)
                        {
                            o += groupByFooterFormatted(previousGroupKey, previousGroupValue, listEndTag);
                        }

                        // add new group heading
                        o += groupByHeaderFormatted(currentGroupKey, currentGroupValue, listStartTag);
                        isFooterNeeded = true;

                        // add to list of groups used
                        if (!string.IsNullOrEmpty(currentGroupKey))
                        {
                            groupByKeyValuesUsed.Add(new KeyValuePair<string, string>(currentGroupKey, currentGroupValue));
                        }
                        previousGroupKey = currentGroupKey;
                        previousGroupValue = currentGroupValue;
                    }
                    o += itemFormatted(item);

                    if (isFirstItem) { isFirstItem = false; }
                } // foreach SPListItem

                // end ul tag
                if (isFooterNeeded)
                {
                    o += groupByFooterFormatted(currentGroupKey, currentGroupValue, listEndTag);
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("685urtertresersdtrseesres6", ex);
                o = null;
            }
            return o;
        }






        /// <summary>
        /// This key is in the SPListItem property bag when doing a custom grouping of items
        /// </summary>
        public static string CustomGroupByPropertyKey = "___[groupKey]___";

        /// <summary>
        /// Re-order SPListItemCollection, grouping items and duplicating them if under more than one group
        /// </summary>
        /// <param name="itemsToOrder"></param>
        /// <param name="valuesToGroupBy">Delegate that returns a list of groups item falls under</param>
        /// <param name="groupValuesUsed">returns the groups found in passed list (except empty group)</param>
        /// <returns></returns>
        private static List<SPListItem> reOrderItemsByGroup(List<SPListItem> itemsToOrder, bool isItemUnderMoreThanOneGroup,
            GroupByKey groupByKey, GroupByValue groupByValue, GroupByKeyValues groupByKeyValues,
            ref Dictionary<int, KeyValuePair<string, string>> groupKeyValuesUsed)
        {
            var itemsOrdered = new List<SPListItem>();
            try
            {
                // init
                if (groupKeyValuesUsed == null) { groupKeyValuesUsed = new Dictionary<int, KeyValuePair<string, string>>(); }
                var emptyGroupKeyValue = new KeyValuePair<string, string>("___[EMPTY]___", null);


                if (itemsToOrder != null && itemsToOrder.Count > 0)
                {
                    // build dictionary of group by values
                    var groups = new SortedDictionary<string, List<SPListItem>>();
                    foreach (SPListItem item in itemsToOrder)
                    {
                        // get groups item is under
                        var groupsItemUnder = new List<KeyValuePair<string, string>>();
                        if (isItemUnderMoreThanOneGroup)
                        {
                            groupsItemUnder = groupByKeyValues(item);
                            if (groupsItemUnder == null || groupsItemUnder.Count == 0)
                            {
                                groupsItemUnder = new List<KeyValuePair<string, string>>() { emptyGroupKeyValue };
                            }
                        }
                        else
                        {
                            var key = groupByKey(item);
                            var value = groupByValue(item);
                            if (string.IsNullOrEmpty(value)) { value = key; }
                            groupsItemUnder.Add(new KeyValuePair<string, string>(key, value));
                        }

                        foreach (var groupKeyValue in groupsItemUnder)
                        {
                            if (!groups.ContainsKey(groupKeyValue.Key))
                            {
                                // add group, it is new
                                groups.Add(groupKeyValue.Key, new List<SPListItem>() { item });
                            }
                            else
                            {
                                // add to existing group
                                groups[groupKeyValue.Key].Add(item);
                            }

                            // add this key/value that item is under to lookup
                            if (groupKeyValue.Key != emptyGroupKeyValue.Key)
                            {
                                groupKeyValuesUsed.Add(item.ID, groupKeyValue);
                            }
                        }
                    }

                    // merge into one list
                    foreach (var group in groups)
                    {
                        foreach (SPListItem item in group.Value) { itemsOrdered.Add(item); }
                    }

                } 
            }
            catch (Exception ex)
            {
                Log.WriteError("456i7r5e4yteetsfdsdsfdfre", ex);
                itemsOrdered = null;
            }
            return itemsOrdered;
        }
        #endregion
    }
}
